#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <unistd.h>
#include <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <cassert>
using namespace std;
#define PROCNUM 4
#define IDLE 0
#define BUSY 1

int task_1()
{
    sleep(1);
    cout << "task_1" << endl;
    return 1;
}
int task_2()
{
    sleep(2);
    cout << "task_2" << endl;
    return 1;
}
int task_3()
{
    sleep(3);
    cout << "task_3" << endl;
    return 1;
}
int task_4()
{
    sleep(4);
    cout << "task_4" << endl;
    return 1;
}
int task_5()
{
    sleep(5);
    cout << "task_5" << endl;
    return 1;
}
int task_6()
{
    sleep(6);
    cout << "task_6" << endl;
    return 1;
}
int task_7()
{
    sleep(7);
    cout << "task_7" << endl;
    return 1;
}
typedef int (*TaskPoint)();
void task_form(vector<TaskPoint> &taskform){
    taskform.push_back(task_1);
    taskform.push_back(task_2);
    taskform.push_back(task_3);
    taskform.push_back(task_4);
    taskform.push_back(task_5);
    taskform.push_back(task_6);
    taskform.push_back(task_7);
}

class SubMember
{
public:
    SubMember(pid_t id, int write_fd, int read_fd) : _id(id), _write_fd(write_fd), _read_fd(read_fd), _status(IDLE)
    {
        _n++;
        char name[1024] = {0};
        snprintf(name, sizeof(name) - 1, "Member #%d", _n);
        _name = name;
    }

public:
    static int _n;
    string _name;
    pid_t _id;
    int _write_fd;
    int _read_fd;
    int _status;
};
int SubMember::_n = 0;
int Check_Member_Exit(vector<SubMember> &form){
    int flag = 0;
    for(int i = 0 ;i < form.size();i++){
        if(form[i]._status == BUSY){
            flag = 1;
        }
    }
    return flag;
}
int Check_Member_Status(vector<SubMember> &form){
    int flag = 1;
    for(int i = 0;i < form.size();i++){
         if (form[i]._status == IDLE)  //check status
        {
            flag = 0; // 1 Indicate availability  0 Indicates no availability
        }
    }
    return flag;
}

int Flush_SubMember_Form(vector<SubMember> &form,int(*action)(vector<SubMember>&))
{
    
    for (int i = 0; i < form.size(); i++)
    {
        int signal = 0;
        int n = read(form[i]._read_fd, &signal, sizeof(signal));
        if(n != EOF){
            form[i]._status = signal;
        }
    }
    return action(form);
}

void Create_Member(vector<SubMember> &memberform, vector<TaskPoint> &taskform)
{
    vector<int> deletefd_w;
    vector<int> deletefd_r;
    for (int i = 0; i < PROCNUM; i++){
        int pipefd_w[2] = {0};
        int n = pipe(pipefd_w);
        assert(n != -1);
        int pipefd_r[2] = {0};
        n = pipe(pipefd_r);
        assert(n != -1);
        pid_t id = fork();
        assert(id >= 0);
        if (!id){
            close(pipefd_w[1]); // child read
            close(pipefd_r[0]);
            for(int i = 0 ; i < deletefd_w.size();i++){      //Close the last duplicate file descriptor
                close(deletefd_w[i]);
            }
            for(int i = 0 ; i < deletefd_r.size();i++){
                close(deletefd_r[i]);
            }
            while (true)
            {
                
                int signal = IDLE;
                n = write(pipefd_r[1], &signal, sizeof(signal));
                assert(n != -1);
                int tasknum;
                n = read(pipefd_w[0], &tasknum, sizeof(int));
                assert(n != -1);
                if (tasknum == -1)
                {
                    cout << getpid() << endl;
                    exit(0);
                }
            
                signal = BUSY;
                n = write(pipefd_r[1], &signal, sizeof(signal));
                assert(n != -1);
                taskform[tasknum](); // execute task;
            }
            exit(0);
        }
        deletefd_w.push_back(pipefd_w[1]);            //Record the last repeated file descriptor
        deletefd_r.push_back(pipefd_r[0]);
        close(pipefd_w[0]);                         // parent write
        close(pipefd_r[1]);                         // parent read
        int flags = fcntl(pipefd_r[0], F_GETFL, 0); // set Non-blocking
        assert(flags != -1);
        flags |= O_NONBLOCK;
        flags = fcntl(pipefd_r[0], F_SETFL, flags);
        assert(flags != -1);
        SubMember member(id, pipefd_w[1], pipefd_r[0]);
        memberform.push_back(move(member)); // move function memory transplant
    }
}
void hoop_buffer(vector<TaskPoint> &taskform, vector<SubMember> &memberform)   //Using circular buffering to achieve load balancing
{
    int index = 0;
    for (int i = 0; i < taskform.size();){
          //wait member
        while(Flush_SubMember_Form(memberform,Check_Member_Status)){
            sleep(1);
        }
        if (memberform[index]._status == IDLE){
            int n = write(memberform[index]._write_fd, &i, sizeof(int));
            assert(n != -1);
            i++;
        }
        index++;
        if (index == SubMember::_n){
            index %= SubMember::_n;
        }
    }
}
void exit_member(vector<SubMember> &memberform){
    
    while(Flush_SubMember_Form(memberform,Check_Member_Exit)){
        sleep(1);
    }
    for (int i = 0; i < memberform.size(); i++){
        int flag = -1;
        int n = write(memberform[i]._write_fd, &flag, sizeof(int));
        assert(n != -1);
    }
}
int main(){
    vector<SubMember> SubMemberForm; // create memberform
    vector<TaskPoint> taskform;      // create taskform
    task_form(taskform);
    Create_Member(SubMemberForm, taskform);
    hoop_buffer(taskform, SubMemberForm); // Use circular buffering to send characters to child processes
    exit_member(SubMemberForm);
    return 0;
}
